<template>
  <el-container class="common-layout">
    <el-header>
      <div class="cityname">{{ cityname }}</div>
      <el-input
        v-model="input1"
        style="width: 240px"
        size="large"
        placeholder="请搜索你所在的城市"
        :prefix-icon="Search"
        @change="handleInputChange"
      />
      <el-select
        v-model="select1"
        style="width: 240px"
        size="large"
        placeholder="选择绘制图形"
        @change="handleSelect1Change"
      >
        <el-option label="直线" value="LineString"></el-option>
        <el-option label="多边形" value="Polygon"></el-option>
        <el-option label="圆" value="Circle"></el-option>
      </el-select>
      <transition name="fade">
        <div class="drawend" v-show="isShow">
          <el-button type="primary" size="large" @click="handleDrawEnd"
            >结束绘制</el-button
          >
          <el-button type="primary" size="large" @click="handleDrawClear"
            >清空绘制</el-button
          >
        </div>
      </transition>
      <el-select
        v-model="select2"
        style="width: 240px"
        size="large"
        placeholder="选择标记类型"
        :disabled="zoom < 13"
        @click="handleSelect2Click"
        @change="handleSelect2Change"
      >
        <el-option label="加油站" value="petrol"></el-option>
        <el-option label="学校" value="school"></el-option>
        <el-option label="医院" value="hospital"></el-option>
      </el-select>
      <span class="zoom">当前缩放级别: {{ zoom }}</span>
    </el-header>
    <el-main id="map">
      <div id="overlay"></div>
    </el-main>
  </el-container>
</template>
<script setup>
import { Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { ref, onMounted, watch } from 'vue'
import { Map, View } from 'ol'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import Vector from 'ol/source/Vector'
import { XYZ } from 'ol/source'
import { GeoJSON } from 'ol/format'
import { Style, Fill, Stroke, Icon } from 'ol/style'
import { getMapData, getIpData, getVectorData } from '@/api/map'
import Draw from 'ol/interaction/Draw'
import { Feature } from 'ol'
import { Point } from 'ol/geom'
import Cluster from 'ol/source/Cluster.js'
import { Circle, Text } from 'ol/style'
import Overlay from 'ol/Overlay'
const input1 = ref('')
const select1 = ref('')
const select2 = ref('')
const cityname = ref('')
const isShow = ref(false)
const zoom = ref(0)
const currentMarktype = ref('')
let map, view, draw, localVector, SearchVector, overlay
//初始化图层
const tileLayer = new TileLayer({
  source: new XYZ({
    url: 'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
  }),
})
//绘制图层
const drawLayer = new VectorLayer({
  source: new Vector({
    features: [],
  }),
})
//标记图层
const markLayer = new VectorLayer({
  source: new Vector({
    features: [],
  }),
})
//聚合图层样式函数变量
const setClusterStyle = (feature) => {
  console.log(feature)
  //获取聚合点数量
  const features = feature.get('features')
  const size = features.length
  let style = new Style()
  //根据数量设置样式
  if (size === 1) {
    style = features[0].getStyle()
  } else {
    //设置聚合点样式
    style = new Style({
      image: new Circle({
        radius: 15,
        stroke: new Stroke({
          color: '#30abfe',
          width: 2,
        }),
        fill: new Fill({
          color: 'rgba(48, 171, 254, 0.3)',
        }),
      }),
      text: new Text({
        text: size.toString(),
        fill: new Fill({
          color: '#fff',
        }),
      }),
    })
  }
  return style
}
//聚合数据源
const clusterSource = new Cluster({
  distance: 50,
  source: markLayer.getSource(),
})
//聚合图层
const clusterLayer = new VectorLayer({
  source: clusterSource,
  style: setClusterStyle,
})
//初始化视图
view = new View({
  center: [114.21, 30.52],
  projection: 'EPSG:4326',
  zoom: 4,
})
onMounted(async () => {
  // 创建canvas元素并设置willReadFrequently属性
  const mapTarget = document.createElement('div')
  mapTarget.id = 'ol-map'
  mapTarget.style.width = '100%'
  mapTarget.style.height = '100%'
  document.getElementById('map').appendChild(mapTarget)

  const canvas = document.createElement('canvas')
  canvas.style.width = '100%'
  canvas.style.height = '100%'
  const ctx = canvas.getContext('2d', { willReadFrequently: true })

  map = new Map({
    target: 'ol-map',
    layers: [tileLayer, drawLayer, clusterLayer],
    view,
    pixelRatio: 1,
  })
  // 初始化overlay - 移到地图初始化之后
  overlay = new Overlay({
    element: document.getElementById('overlay'),
    positioning: 'bottom-center',
    autoPan: true,
    autoPanAnimation: {
      duration: 250,
    },
  })
  map.addOverlay(overlay)
  // 添加鼠标移入事件
  map.on('pointermove', (e) => {
    let foundFeature = null
    map.forEachFeatureAtPixel(e.pixel, (feature) => {
      // 检查要素是否具有需要的属性
      if (feature.get('name') && feature.get('adcode')) {
        foundFeature = feature
        return true
      }
      return false
    })
    if (foundFeature) {
      // 如果有所需属性的要素，显示overlay
      const name = foundFeature.get('name')
      const adcode = foundFeature.get('adcode')
      const level = foundFeature.get('level') || '未知'
      const center = foundFeature.get('center')
      const element = overlay.getElement()
      element.innerHTML = `
      <div class="overlay-content">
        <h3>${name}</h3>
        <p>行政区划:${adcode}</p>
        <p>级别:${level}</p>
        <p>中心坐标:${center}</p>
      </div>`
      overlay.setPosition(center)
    } else {
      // 没有则隐藏overlay
      overlay.setPosition(undefined)
    }
  })
  const res = await getIpData()
  console.log(res)
  cityname.value = res.city
  const ipcode = res.adcode
  //获取矢量图层范围数据(中心坐标)
  const res2 = await getVectorData(ipcode)
  console.log(res2)
  const centercoord = res2.features[0].properties.center
  console.log(centercoord)
  //两秒后自动获取当前位置
  setTimeout(() => {
    localVector = new VectorLayer({
      source: new Vector({
        url: `https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=${ipcode}`,
        format: new GeoJSON(),
      }),
      style: new Style({
        fill: new Fill({
          color: 'rgba(255, 0, 0, 0.5)',
        }),
        stroke: new Stroke({
          color: 'rgba(0, 0, 255, 0.5)',
          width: 2,
        }),
      }),
    })
    map.addLayer(localVector)
    //移动view动画
    view.animate({
      center: centercoord,
      duration: 2000,
      projection: 'EPSG:4326',
      zoom: 8,
    })
  }, 2000)
  //监听地图移动结束事件
  map.on('moveend', () => {
    zoom.value = Math.floor(view.getZoom())
  })
  //监听地图点击事件,仅限于有选中标记类型时
  map.on('click', (e) => {
    if (currentMarktype.value) {
      const coordinate = e.coordinate
      console.log(coordinate)
      const feature = new Feature({
        geometry: new Point(coordinate),
        //为后面按类型聚合做准备
        // type: currentMarktype.value,
      })
      feature.setStyle(
        new Style({
          image: new Icon({
            src: `/${currentMarktype.value}.png`,
            scale: 0.2,
          }),
        })
      )
      markLayer.getSource().addFeature(feature)
    }
  })
  //监听zoom值的变化
  watch(
    zoom,
    (newValue) => {
      // 检查图层是否存在
      if (localVector) {
        localVector.setVisible(newValue <= 10)
      }
      if (SearchVector) {
        SearchVector.setVisible(newValue <= 10)
      }
      if (newValue < 13) {
        select2.value = ''
        currentMarktype.value = ''
      }
    },
    {
      immediate: true, // 立即执行一次
    }
  )
})
//输入框改变事件
const handleInputChange = async (value) => {
  const res = await getMapData(value)
  console.log(res)
  const citycode = res.geocodes[0].adcode
  console.log(citycode)
  //获取矢量图层范围数据(中心坐标)
  const res2 = await getVectorData(citycode)
  console.log(res2)
  const centercoord = res2.features[0].properties.center
  console.log(centercoord)
  //移动view动画
  view.animate({
    center: centercoord,
    duration: 2000,
    projection: 'EPSG:4326',
    zoom: 8,
  })
  //移除除drawLayer外的所有矢量图层
  const layers = map.getLayers()
  for (let i = layers.getLength() - 1; i >= 0; i--) {
    const layer = layers.item(i)
    if (layer instanceof VectorLayer && layer !== drawLayer) {
      map.removeLayer(layer)
    }
  }
  //添加新的矢量图层
  SearchVector = new VectorLayer({
    source: new Vector({
      url: `https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=${citycode}`,
      format: new GeoJSON(),
    }),
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 0, 0, 0.5)',
      }),
      stroke: new Stroke({
        color: 'rgba(0, 0, 255, 0.5)',
      }),
    }),
  })
  map.addLayer(SearchVector)
}
//选择绘制图形改变事件
const handleSelect1Change = (value) => {
  console.log(value)
  //如果有画笔,则移除
  if (draw) {
    map.removeInteraction(draw)
  }
  //创建新画笔并添加到地图
  draw = new Draw({
    type: value,
    source: drawLayer.getSource(),
  })
  //监听画笔
  draw.on('drawstart', (e) => {
    console.log(e)
  })
  map.addInteraction(draw)
  isShow.value = true
}
//结束绘制
const handleDrawEnd = () => {
  map.removeInteraction(draw)
  select1.value = ''
  isShow.value = false
}
//清空绘制
const handleDrawClear = () => {
  drawLayer.getSource().clear()
  map.removeInteraction(draw)
  select1.value = ''
  isShow.value = false
}
//选择标记类型点击事件
const handleSelect2Click = (event) => {
  if (zoom.value < 13) {
    ElMessage({
      message: '请缩放到13级以上',
      type: 'warning',
      duration: 3000,
    })
    // 阻止下拉框打开
    if (event) {
      event.preventDefault()
      event.stopPropagation()
    }
    return false
  }
  return true
}
// 添加一个方法来检查是否可以打点
const checkCanMark = () => {
  return zoom.value >= 13
}
//选择标记类型改变事件
const handleSelect2Change = (value) => {
  if (checkCanMark()) {
    currentMarktype.value = value
    console.log('已设置当前标记类型:', value)
  } else {
    select2.value = ''
    currentMarktype.value = ''
  }
}
</script>
<style lang="scss" scoped>
//定义一个尺寸变量
$size: 120px;
.common-layout {
  height: 100vh;
  .el-header {
    width: 100%;
    height: 80px;
    background-color: #3454f3;
    padding: 0;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    .cityname {
      font-size: 20px;
      color: #fff;
      margin-left: 20px;
      margin-right: $size;
    }
    .el-input,
    .el-select {
      margin-right: $size;
    }
    .drawend {
      position: fixed;
      right: 20px;
      top: 90px;
      z-index: 1;
    }
    .fade-enter-active,
    .fade-leave-active {
      transition: opacity 0.5s;
    }
    .fade-enter-from,
    .fade-leave-to {
      opacity: 0;
    }
    .zoom {
      color: #fff;
    }
  }
  #map {
    width: 100%;
    height: calc(100vh - 80px);
    padding: 0;
    position: relative;

    #ol-map {
      width: 100%;
      height: 100%;
    }
  }
  #overlay {
    position: absolute;
    width: max-content;
    background-color: white;
    padding: 10px;
    border-radius: 5px;
    border: 1px solid #ccc;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  }
}
</style>
